package org.benjamin.lending.trusteeship;

import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.Map;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.benjamin.lending.domain.entity.BorrowInfo;
import org.benjamin.lending.domain.entity.MemberInfo;
import org.benjamin.lending.domain.entity.RequestStatus;
import org.benjamin.lending.domain.entity.TrusteeshipRequest;
import org.benjamin.lending.domain.trusteeship.RequestParameter;
import org.benjamin.lending.repository.BorrowInfoRepository;
import org.benjamin.lending.repository.MemberInfoRepository;
import org.benjamin.lending.repository.TrusteeshipRequestRepository;
import org.springframework.beans.factory.annotation.Autowired;

import com.fasterxml.jackson.databind.ObjectMapper;

/**
 * 该类是抽象类，提供可重用的类，只要继承该类并实现详细的提交方式
 * 达到可重用实现类需要了解该类的生命周期，已达到更高效的修改并实现。
 * 该类的生命周期为request方法为请求入口。
 * request()->beforeRequest()->buildUserIdIdentity()->prceessRequest()->buildAbutmentUrl()->signatureRequest()->afterRequest();
 * beforeRequest:是提供托管等合作商的共同参数；
 * buildUserIdIdentity：用户在合作商的唯一标识，标识的可以由子类重写；
 * prceessRequest：主要提交合作商的核心参数
 * buildAbutmentUrl：构建合作商对接的Url参数，基本都相同，但不排除特别情况有特殊URL链接可以通过子类重写；
 * signatureRequest：签名加密，抽象方法，由于每种操作的加密规则不一样，需要在子类重写；
 * afterRequest：参数封装之后，上面主要是与托管等合作商对接参数。该方法主要实现业务处理登记。
 * @author 黄文杰
 *
 */
public abstract class AbstractService {
	
	protected boolean asynchronous = false;
	
	protected String abutmentUrl;
	
	private final Logger logger = LogManager.getLogger();
	
	@Autowired
	private MemberInfoRepository memberInfoRepository;

	@Autowired
	private BorrowInfoRepository borrowInfoRepository;
	
	@Autowired
	private TrusteeshipRequestRepository trusteeshipRequestRepository;

	/**
	 * 
	 * @param username
	 * @param parameterMap
	 * @return
	 */
	public RequestParameter request(String username,Map<String,Object> parameterMap){
		return this.request(username,null,parameterMap);
	}
	
	public RequestParameter request(String username,Integer borrowId,Map<String,Object> parameterMap){
		try{
			TrusteeshipRequest trusteeshipRequest = new TrusteeshipRequest();
			trusteeshipRequest.setOrigData(new ObjectMapper().writeValueAsString(parameterMap));
			
			BorrowInfo borrowInfo = null;
			if(borrowId != null){
				borrowInfo = this.borrowInfoRepository.findOne(borrowId);
				trusteeshipRequest.setBid(borrowId);
			}
			
			Map<String,Object> requestMap = new HashMap<String, Object>();
			String requestId = new SimpleDateFormat("yyMMddHHss").format(System.currentTimeMillis());
			this.beforeRequest(requestMap,requestId,borrowInfo);
			MemberInfo memberInfo = this.memberInfoRepository.findByUsername(username);
			if(memberInfo != null){
				trusteeshipRequest.setUid(memberInfo.getId());
			}

			

			if(memberInfo != null){
				logger.info("查询用户结果：{}",memberInfo.getUsername());
			}
			this.buildUserIdIdentity(requestMap, username);
			this.processRequest(requestMap,memberInfo,borrowInfo,parameterMap);
			this.buildAbutmentUrl(requestMap);
			String rulesRequest = this.signatureRequest(requestMap);

			trusteeshipRequest.setRulesRequest(rulesRequest);
			trusteeshipRequest.setStatus(RequestStatus.SENDING);
			//封装数据组装完毕
			trusteeshipRequest.setUrl(this.abutmentUrl);
			trusteeshipRequest.setId(requestId);
			trusteeshipRequest.setPackData(new ObjectMapper().writeValueAsString(requestMap));
			trusteeshipRequest.setCreateTime(new Timestamp(System.currentTimeMillis()));
			
			this.afterRequest(parameterMap, memberInfo,borrowInfo,trusteeshipRequest);
			
			this.initTrusteeshipRequestMemberInfo(trusteeshipRequest, memberInfo);
			this.trusteeshipRequestRepository.save(trusteeshipRequest);
			RequestParameter parameter = new RequestParameter(requestMap, this.abutmentUrl);
			return parameter;
		}catch(Exception e){
			logger.error(e.getMessage(),e);
		}
		return null;
	}
	
	/**
	 * 业务回掉操作
	 */
	public void response(TrusteeshipRequest trusteeshipRequest,Map<String,Object> responseMap){
		
		if(this.signatureResponseValidity(trusteeshipRequest,responseMap)){
			logger.info("签名校验成功数据是合法的。");
			this.beforeResponse(responseMap);
			this.processResponse(trusteeshipRequest, responseMap);
		}else{
			logger.error("签名校验失败");
		}
		this.trusteeshipRequestRepository.save(trusteeshipRequest);
	}

	protected boolean signatureResponseValidity(TrusteeshipRequest trusteeshipRequest,Map<String, Object> responseMap) {
		// TODO Auto-generated method stub
		return false;
	}

	/**
	 * 构建托管唯一标识字符串
	 * @param requestMap
	 * @param username
	 */
	protected void buildUserIdIdentity(Map<String,Object> requestMap,String username) {
		
	}
	
	/**
	 * 封装数据前的准备
	 * @param requestMap
	 * @param requestId
	 */
	protected void beforeRequest(Map<String,Object> requestMap,String requestId,BorrowInfo borrowInfo){
		
	}
	
	protected void initTrusteeshipRequestMemberInfo(TrusteeshipRequest trusteeshipRequest,MemberInfo memberInfo){
		trusteeshipRequest.setUid(memberInfo.getId());
	}
	
	/**
	 * 您所需要封装的实际内容
	 * @param requestMap
	 * @param memberInfo
	 * @param parameterMap
	 */
	protected abstract void processRequest(Map<String,Object> requestMap, MemberInfo memberInfo, BorrowInfo borrowInfo, Map<String,Object>parameterMap);
	
	protected  abstract String signatureRequest(Map<String, Object> requestMap);

	/**
	 * 封装完毕后可能需要调用
	 * @param parameterMap
	 */
	protected abstract void afterRequest(Map<String,Object> parameterMap,MemberInfo memberInfo,BorrowInfo borrowInfo,TrusteeshipRequest trusteeshipRequest);

	protected  abstract String[] signatureResponse(Map<String,Object> responseMap);
	


	protected void buildAbutmentUrl(Map<String, Object> requestMap) {
		
	}
	
	protected String[] beforeResponse(Map<String, Object> responseMap){
		return new String[0];
	}

	protected abstract void processResponse(TrusteeshipRequest trusteeshipRequest, Map<String, Object> responseMap);

	public boolean isAsynchronous() {
		return asynchronous;
	}
}
